package api

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/julienschmidt/httprouter"
	"notabug.org/ropemann/imabon/src/entities/post"
	"notabug.org/ropemann/imabon/src/entities/thread"
	"notabug.org/ropemann/imabon/src/routes/utils"
	"notabug.org/ropemann/imabon/src/service/boardService"
	"notabug.org/ropemann/imabon/src/service/postService"
	"notabug.org/ropemann/imabon/src/service/threadService"
)

var PersistThread = threadService.PersistThread
var Create = postService.Create

func sendJsonResponse(w http.ResponseWriter, status int, v any) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	jsonResp, err := json.Marshal(v)
	if err != nil {
		log.Printf("Error happened in JSON marshal. Err: %s\n", err)
		w.Write([]byte(err.Error()))
	}
	w.Write(jsonResp)
}

func RegisterApiRoutes(router *httprouter.Router) {
	apiPrefix := os.Getenv("API_PREFIX")
	if len(apiPrefix) == 0 {
		apiPrefix = "api"
		os.Setenv("API_PREFIX", apiPrefix)
	}
	router.GET(fmt.Sprintf("/%s/boards", apiPrefix), GetAllBoards)
	router.GET(fmt.Sprintf("/%s/recent", apiPrefix), GetMostRecentThreads)
	router.GET(fmt.Sprintf("/%s/content/:board", apiPrefix), GetAllThreadsByBoard)
	router.GET(fmt.Sprintf("/%s/content/:board/:thread", apiPrefix), GetThreadById)

	router.POST(fmt.Sprintf("/%s/thread/:board", apiPrefix), CreateThread)
	router.POST(fmt.Sprintf("/%s/post/:board/:thread", apiPrefix), CreatePost)
}

func GetMostRecentThreads(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
	recentThreads := threadService.GetMostRecentThreads()
	sendJsonResponse(w, http.StatusOK, recentThreads)
}

func GetAllThreadsByBoard(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
	threads := threadService.GetAllThreadsByBoard(ps.ByName("board"))
	sendJsonResponse(w, http.StatusOK, threads)
}

func GetThreadById(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
	thread := threadService.GetThreadById(ps.ByName("board"), ps.ByName("thread"))
	sendJsonResponse(w, http.StatusOK, thread)
}

func CreateThread(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
	req.ParseForm()
	imgBase64Str, _ := utils.ProcessRequestImage(req)
	thread := thread.NewThread(
		req.FormValue("threadTitle"),
		req.FormValue("authorName"),
		req.FormValue("comment"),
		imgBase64Str)

	threadId, err := PersistThread(ps.ByName("board"), *thread)
	if err != nil {
		errorMsg := fmt.Sprintf("Error occured on thread creation: %s", err)
		sendJsonResponse(w, http.StatusBadRequest, errorMsg)
		return
	}

	sendJsonResponse(w, http.StatusOK, threadId)
}

func CreatePost(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
	req.ParseForm()
	imgBase64Str, _ := utils.ProcessRequestImage(req)
	post := post.NewPost(req.FormValue("authorName"), req.FormValue("comment"), imgBase64Str)

	affected, err := Create(ps.ByName("board"), ps.ByName("thread"), *post)
	if err != nil || affected == 0 {
		errorMsg := fmt.Sprintf("Error occured on thread creation: %s", err)
		sendJsonResponse(w, http.StatusBadRequest, errorMsg)
		return
	}

	sendJsonResponse(w, http.StatusOK, affected)
}

func GetAllBoards(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
	boards := boardService.GetAllBoards()
	sendJsonResponse(w, http.StatusOK, boards)
}
